package snucse.teamd.math;

import java.util.Vector;

public class Projection {
	Edge sepPlane;
	Vector<Vec2> originalVec2;
	Vector<Vec2> projectVec2;
	Edge totalEdge;
	private Vec2 collisionVec2; //candidate of contact point;
	Vec2 sepAxisProject;
	Edge sepAxis;
	
	public Projection(Edge sepAxis_, Edge sepPlane_, Edge e, Vec2 sepAxisProject_){
		originalVec2 = new Vector<Vec2>();
		projectVec2 = new Vector<Vec2>();
		totalEdge = new Edge(e.getV1().project(sepPlane_),e.getV2().project(sepPlane_));
		sepPlane = new Edge(sepPlane_);
		originalVec2.addElement(e.getV1());
		originalVec2.addElement(e.getV2());
		projectVec2.addElement(e.getV1().project(sepPlane_));
		projectVec2.addElement(e.getV2().project(sepPlane_));
		collisionVec2=new Vec2(9999f,9999f);
		sepAxisProject=new Vec2(sepAxisProject_);
		sepAxis=sepAxis_;
	}
	
	public double length(){
		return totalEdge.length();
	}
	public Edge getTotalEdge() {
		return totalEdge;
	}
	public void addEdge(Edge e){
		Vec2 pV1,pV2;
		pV1=e.getV1().project(sepPlane);
		pV2=e.getV2().project(sepPlane);
		originalVec2.addElement(e.getV1());
		originalVec2.addElement(e.getV2());
		projectVec2.addElement(e.getV1().project(sepPlane));
		projectVec2.addElement(e.getV2().project(sepPlane));
		
		double max = 0f;
		Edge maxEdge = new Edge(totalEdge);
		max = Vec2.distance(totalEdge.getV1(), totalEdge.getV2());
		if (Vec2.distance(pV1, pV2) > max){
			max=Vec2.distance(pV1, pV2);
			maxEdge.setV1(pV1);
			maxEdge.setV2(pV2);
		}
		if (Vec2.distance(totalEdge.getV1(), pV1) > max){
			max=Vec2.distance(totalEdge.getV1(), pV1);
			maxEdge.setV1(totalEdge.getV1());
			maxEdge.setV2(pV1);
		}
		if (Vec2.distance(totalEdge.getV1(), pV2) > max){
			max=Vec2.distance(totalEdge.getV1(), pV2);
			maxEdge.setV1(totalEdge.getV1());
			maxEdge.setV2(pV2);
		}
		if (Vec2.distance(totalEdge.getV2(), pV1) > max){
			max=Vec2.distance(totalEdge.getV2(), pV1);
			maxEdge.setV1(totalEdge.getV2());
			maxEdge.setV2(pV1);
		}
		if (Vec2.distance(totalEdge.getV2(), pV2) > max){
			max=Vec2.distance(totalEdge.getV2(), pV2);
			maxEdge.setV1(totalEdge.getV2());
			maxEdge.setV2(pV2);
		}
		totalEdge = maxEdge;		
	}
	public double overlapLength(Projection p){
		float eps = 0.01f, eps2=0.01f, eps3=1f;
		double dist;
		//if (p.totalEdge.length() * Vec2.distance(totalEdge.getV2(), p.totalEdge.getV2()) < eps) return false;
		//if (p.totalEdge.length() * Vec2.distance(totalEdge.getV1(), p.totalEdge.getV2()) < eps) return false;
		Vector<Vec2> innerEList=new Vector<Vec2>();
		Vector<Vec2> innerEOList=new Vector<Vec2>();
		if (Math.abs(
				Vec2.dot(Vec2.minus(totalEdge.getV1(),p.totalEdge.getV1()) 
						, Vec2.minus(totalEdge.getV1(),p.totalEdge.getV2()))
				+ Vec2.distance(totalEdge.getV1(), p.totalEdge.getV1()) 
					* Vec2.distance(totalEdge.getV1(), p.totalEdge.getV2())
				) < eps){
			innerEList.addElement(totalEdge.getV1());
			innerEOList.addElement(findOriginal(totalEdge.getV1()));
		}if (Math.abs(
				Vec2.dot(Vec2.minus(p.totalEdge.getV1(),totalEdge.getV1()) 
						, Vec2.minus(p.totalEdge.getV1(),totalEdge.getV2()))
				+ Vec2.distance(p.totalEdge.getV1(), totalEdge.getV1()) 
					* Vec2.distance(p.totalEdge.getV1(), totalEdge.getV2())
				) < eps){
			innerEList.addElement(p.totalEdge.getV1());
			innerEOList.addElement(p.findOriginal(p.totalEdge.getV1()));
		}
		if (Math.abs(
				Vec2.dot(Vec2.minus(totalEdge.getV2(),p.totalEdge.getV1()) 
						, Vec2.minus(totalEdge.getV2(),p.totalEdge.getV2()))
				+ Vec2.distance(totalEdge.getV2(), p.totalEdge.getV1()) 
					* Vec2.distance(totalEdge.getV2(), p.totalEdge.getV2())
				) < eps){
			innerEList.addElement(totalEdge.getV2());
			innerEOList.addElement(findOriginal(totalEdge.getV2()));
		}if (Math.abs(
				Vec2.dot(Vec2.minus(p.totalEdge.getV2(),totalEdge.getV1()) 
						, Vec2.minus(p.totalEdge.getV2(),totalEdge.getV2()))
				+ Vec2.distance(p.totalEdge.getV2(), totalEdge.getV1()) 
					* Vec2.distance(p.totalEdge.getV2(), totalEdge.getV2())
				) < eps){
			innerEList.addElement(p.totalEdge.getV2());
			innerEOList.addElement(p.findOriginal(p.totalEdge.getV2()));
		}
		
		if (innerEList.size()<2) return -1;
		
		
		//
		for(int i=0; i<innerEList.size(); i++){
			dist = Vec2.distance(this.sepAxisProject,innerEList.get(i));
			if (Vec2.distance(sepAxis.getV1(),innerEOList.get(i)/* this.collisionVec2*/)<eps2 || Vec2.distance(sepAxis.getV2(),innerEOList.get(i)/*this.collisionVec2*/)<eps2)
				continue;
			if ( dist > eps && dist < Vec2.distance(this.sepAxisProject, this.collisionVec2.project(sepPlane))){
				this.collisionVec2 = innerEOList.get(i);
			}
		}
		/*/not contact sep Axis
		eps3=10f;
				if (Math.abs(
						Vec2.dot(Vec2.minus(this.collisionVec2,sepAxis.getV1()) 
								, Vec2.minus(this.collisionVec2,sepAxis.getV2()))
						+ Vec2.distance(this.collisionVec2, sepAxis.getV1()) 
							* Vec2.distance(this.collisionVec2, sepAxis.getV2())
						) > eps3) return 999;
				///*/
		
		return Vec2.distance(innerEList.get(0), innerEList.get(1));
	}

	public Vec2 getCollisionVec2() {
		return collisionVec2;
	}
	
	public Vec2 findOriginal(Vec2 pV){
		double eps=0.01f;
		for (int i=0;i<originalVec2.size();i++){
			if (Vec2.distance(projectVec2.get(i),pV) < eps){
				return originalVec2.get(i);
			}
		}
		
		return new Vec2();
	}

	
}
